import { Injectable, NestInterceptor, ExecutionContext, CallHandler, HttpStatus } from '@nestjs/common'
import { Observable } from 'rxjs'
import { map, tap, catchError } from 'rxjs/operators'
import { Request, Response } from 'express'
import { LoggerService } from '../../logger/logger.service'
import { Reflector } from '@nestjs/core'

/**
 * 标准API响应接口
 */
export interface ApiResponse<T = any> {
  success: boolean
  statusCode: number
  message: string
  data?: T
  meta?: {
    timestamp: string
    requestId?: string
    duration?: number
    pagination?: {
      page: number
      limit: number
      total: number
      totalPages: number
      hasNext: boolean
      hasPrev: boolean
    }
  }
  errors?: any
}

/**
 * 分页响应数据接口
 */
export interface PaginatedData<T = any> {
  items: T[]
  total: number
  page: number
  limit: number
  totalPages: number
  hasNext: boolean
  hasPrev: boolean
}

/**
 * 跳过响应转换的装饰器键
 */
export const SKIP_RESPONSE_TRANSFORM = 'skipResponseTransform'

/**
 * 自定义响应消息装饰器键
 */
export const RESPONSE_MESSAGE = 'responseMessage'

/**
 * 响应转换拦截器
 * 统一处理API响应格式，提供标准化的响应结构
 */
@Injectable()
export class ResponseTransformInterceptor<T> implements NestInterceptor<T, ApiResponse<T>> {
  constructor(
    private readonly logger: LoggerService,
    private readonly reflector: Reflector
  ) {}

  intercept(context: ExecutionContext, next: CallHandler): Observable<ApiResponse<T>> {
    const request = context.switchToHttp().getRequest<Request>()
    const response = context.switchToHttp().getResponse<Response>()
    const startTime = Date.now()
    const requestId = (request as any).requestId || 'unknown'

    // 检查是否跳过响应转换
    const skipTransform = this.reflector.getAllAndOverride<boolean>(SKIP_RESPONSE_TRANSFORM, [
      context.getHandler(),
      context.getClass()
    ])

    if (skipTransform) {
      return next.handle()
    }

    // 获取自定义响应消息
    const customMessage = this.reflector.getAllAndOverride<string>(RESPONSE_MESSAGE, [
      context.getHandler(),
      context.getClass()
    ])

    return next.handle().pipe(
      map(data => {
        const duration = Date.now() - startTime
        const statusCode = response.statusCode

        // 构建响应对象
        const apiResponse: ApiResponse<T> = {
          success: statusCode >= 200 && statusCode < 300,
          statusCode,
          message: customMessage || this.getDefaultMessage(statusCode, request.method),
          data: this.transformData(data),
          meta: {
            timestamp: new Date().toISOString(),
            requestId,
            duration
          }
        }

        // 添加分页信息（如果存在）
        if (this.isPaginatedData(data)) {
          apiResponse.meta!.pagination = {
            page: data.page,
            limit: data.limit,
            total: data.total,
            totalPages: data.totalPages,
            hasNext: data.hasNext,
            hasPrev: data.hasPrev
          }
          apiResponse.data = data.items as any
        }

        // 记录成功响应日志
        this.logger.debug('API响应成功', {
          method: request.method,
          url: request.url,
          statusCode,
          duration,
          requestId,
          dataSize: this.getDataSize(apiResponse.data)
        })

        return apiResponse
      }),
      catchError(error => {
        const duration = Date.now() - startTime

        // 记录错误响应日志
        this.logger.error('API响应失败', error.stack, {
          method: request.method,
          url: request.url,
          duration,
          requestId,
          error: error.message
        })

        throw error
      })
    )
  }

  /**
   * 转换响应数据
   * @param data 原始数据
   * @returns 转换后的数据
   */
  private transformData(data: any): any {
    // 如果数据为null或undefined，返回null
    if (data === null || data === undefined) {
      return null
    }

    // 如果是分页数据，返回items
    if (this.isPaginatedData(data)) {
      return data.items
    }

    // 如果是数组，直接返回
    if (Array.isArray(data)) {
      return data
    }

    // 如果是对象，检查是否有特殊结构
    if (typeof data === 'object') {
      // 检查是否是包装过的响应
      if (Object.prototype.hasOwnProperty.call(data, 'data') && Object.keys(data).length === 1) {
        return data.data
      }
    }

    return data
  }

  /**
   * 检查是否为分页数据
   * @param data 数据对象
   * @returns 是否为分页数据
   */
  private isPaginatedData(data: any): data is PaginatedData {
    return (
      data &&
      typeof data === 'object' &&
      Array.isArray(data.items) &&
      typeof data.total === 'number' &&
      typeof data.page === 'number' &&
      typeof data.limit === 'number'
    )
  }

  /**
   * 获取默认响应消息
   * @param statusCode HTTP状态码
   * @param method HTTP方法
   * @returns 默认消息
   */
  private getDefaultMessage(statusCode: number, method: string): string {
    if (statusCode >= 200 && statusCode < 300) {
      switch (method.toUpperCase()) {
        case 'GET':
          return '查询成功'
        case 'POST':
          return '创建成功'
        case 'PUT':
        case 'PATCH':
          return '更新成功'
        case 'DELETE':
          return '删除成功'
        default:
          return '操作成功'
      }
    }

    switch (statusCode) {
      case HttpStatus.BAD_REQUEST:
        return '请求参数错误'
      case HttpStatus.UNAUTHORIZED:
        return '未授权访问'
      case HttpStatus.FORBIDDEN:
        return '禁止访问'
      case HttpStatus.NOT_FOUND:
        return '资源不存在'
      case HttpStatus.CONFLICT:
        return '资源冲突'
      case HttpStatus.INTERNAL_SERVER_ERROR:
        return '服务器内部错误'
      default:
        return '操作失败'
    }
  }

  /**
   * 获取数据大小（用于日志记录）
   * @param data 数据
   * @returns 数据大小描述
   */
  private getDataSize(data: any): string {
    if (!data) return '0'

    if (Array.isArray(data)) {
      return `${data.length} items`
    }

    if (typeof data === 'object') {
      const keys = Object.keys(data)
      return `${keys.length} fields`
    }

    return 'single value'
  }
}

/**
 * 性能监控拦截器
 * 监控API性能，记录慢查询和异常情况
 */
@Injectable()
export class PerformanceInterceptor implements NestInterceptor {
  constructor(private readonly logger: LoggerService) {}

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest<Request>()
    const startTime = Date.now()
    const startMemory = process.memoryUsage()
    const requestId = (request as any).requestId || 'unknown'

    return next.handle().pipe(
      tap(() => {
        const duration = Date.now() - startTime
        const endMemory = process.memoryUsage()
        const memoryDiff = {
          rss: endMemory.rss - startMemory.rss,
          heapUsed: endMemory.heapUsed - startMemory.heapUsed,
          heapTotal: endMemory.heapTotal - startMemory.heapTotal,
          external: endMemory.external - startMemory.external
        }

        const performanceData = {
          method: request.method,
          url: request.url,
          duration,
          requestId,
          memoryUsage: {
            before: startMemory,
            after: endMemory,
            diff: memoryDiff
          },
          userAgent: request.get('User-Agent'),
          ip: request.ip,
          userId: (request as any).user?.id
        }

        // 慢查询警告（超过1秒）
        if (duration > 1000) {
          this.logger.warn('慢查询检测', {
            ...performanceData,
            threshold: '1000ms',
            severity: duration > 5000 ? 'critical' : 'warning'
          })
        }

        // 内存使用异常警告（增长超过50MB）
        if (memoryDiff.heapUsed > 50 * 1024 * 1024) {
          this.logger.warn('内存使用异常', {
            ...performanceData,
            memoryIncrease: `${Math.round(memoryDiff.heapUsed / 1024 / 1024)}MB`
          })
        }

        // 记录性能日志（仅在开发环境或调试模式）
        if (process.env.NODE_ENV === 'development' || process.env.LOG_PERFORMANCE === 'true') {
          this.logger.debug('API性能监控', performanceData)
        }
      }),
      catchError(error => {
        const duration = Date.now() - startTime

        this.logger.error('API执行异常', error.stack, {
          method: request.method,
          url: request.url,
          duration,
          requestId,
          error: error.message,
          userAgent: request.get('User-Agent'),
          ip: request.ip,
          userId: (request as any).user?.id
        })

        throw error
      })
    )
  }
}

/**
 * 缓存拦截器
 * 为GET请求提供缓存功能
 */
@Injectable()
export class CacheInterceptor implements NestInterceptor {
  private cache = new Map<string, { data: any; timestamp: number; ttl: number }>()
  private readonly defaultTTL = 5 * 60 * 1000 // 5分钟

  constructor(private readonly logger: LoggerService) {
    // 定期清理过期缓存
    setInterval(() => this.cleanExpiredCache(), 60 * 1000) // 每分钟清理一次
  }

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest<Request>()
    const method = request.method.toUpperCase()

    // 只缓存GET请求
    if (method !== 'GET') {
      return next.handle()
    }

    // 检查是否跳过缓存
    const skipCache = this.reflector.getAllAndOverride<boolean>('skipCache', [context.getHandler(), context.getClass()])

    if (skipCache) {
      return next.handle()
    }

    const cacheKey = this.generateCacheKey(request)
    const cachedData = this.getFromCache(cacheKey)

    if (cachedData) {
      this.logger.debug('缓存命中', {
        url: request.url,
        cacheKey,
        requestId: (request as any).requestId
      })
      return new Observable(observer => {
        observer.next(cachedData)
        observer.complete()
      })
    }

    return next.handle().pipe(
      tap(data => {
        // 获取缓存TTL
        const cacheTTL =
          this.reflector.getAllAndOverride<number>('cacheTTL', [context.getHandler(), context.getClass()]) ||
          this.defaultTTL

        this.setCache(cacheKey, data, cacheTTL)

        this.logger.debug('数据已缓存', {
          url: request.url,
          cacheKey,
          ttl: cacheTTL,
          requestId: (request as any).requestId
        })
      })
    )
  }

  private reflector = new Reflector()

  /**
   * 生成缓存键
   * @param request 请求对象
   * @returns 缓存键
   */
  private generateCacheKey(request: Request): string {
    const url = request.url
    const query = JSON.stringify(request.query)
    const userId = (request as any).user?.id || 'anonymous'
    return `${url}:${query}:${userId}`
  }

  /**
   * 从缓存获取数据
   * @param key 缓存键
   * @returns 缓存数据或null
   */
  private getFromCache(key: string): any | null {
    const cached = this.cache.get(key)
    if (!cached) {
      return null
    }

    const now = Date.now()
    if (now - cached.timestamp > cached.ttl) {
      this.cache.delete(key)
      return null
    }

    return cached.data
  }

  /**
   * 设置缓存
   * @param key 缓存键
   * @param data 数据
   * @param ttl 生存时间（毫秒）
   */
  private setCache(key: string, data: any, ttl: number): void {
    this.cache.set(key, {
      data,
      timestamp: Date.now(),
      ttl
    })
  }

  /**
   * 清理过期缓存
   */
  private cleanExpiredCache(): void {
    const now = Date.now()
    let cleanedCount = 0

    for (const [key, cached] of this.cache.entries()) {
      if (now - cached.timestamp > cached.ttl) {
        this.cache.delete(key)
        cleanedCount++
      }
    }

    if (cleanedCount > 0) {
      this.logger.debug('缓存清理完成', {
        cleanedCount,
        remainingCount: this.cache.size
      })
    }
  }

  /**
   * 清空所有缓存
   */
  public clearAllCache(): void {
    const count = this.cache.size
    this.cache.clear()
    this.logger.log('所有缓存已清空')
  }

  /**
   * 清空指定模式的缓存
   * @param pattern 匹配模式
   */
  public clearCacheByPattern(pattern: string): void {
    let clearedCount = 0
    const regex = new RegExp(pattern)

    for (const key of this.cache.keys()) {
      if (regex.test(key)) {
        this.cache.delete(key)
        clearedCount++
      }
    }

    this.logger.log('模式缓存已清空')
  }
}
